package basketball

import (
	"encoding/json"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	global2 "longmen/server/config/global"
	"longmen/server/internal/services/nami/config"
	"longmen/server/internal/services/nami/services"
	"longmen/server/pkg/common/helper/encrypt"
	"longmen/server/pkg/db/mysql/models/models_sports"
	"time"
)

type InsertMatchInterface interface {
	Get() models_sports.BasketballMatch
}

type UpdateMatchInterface interface {
	GetUpdate() models_sports.BasketballMatch
}

func Sum(numbers []int) int {
	sum := 0
	count := len(numbers)
	for i := 0; i < count; i++ {
		sum += numbers[i]
	}
	return sum
}

var (
	matchFiled = []string{
		"id", "competition_id", "home_team_id", "away_team_id", "kind", "period_count",
		"status_id", "match_time", "neutral", "home_scores", "away_scores",
		"home_position", "away_position", "mlive", "intelligence", "venue_id", "season_id",
		"stage_id", "group_num", "round_num", "updated_at", "over_time_scores",
		"home_en", "away_en", "comp_short_en",
	}
	matchTempField = []string{
		"id", "match_id", "match_time", "sport_id", "comp",
		"comp_short_zh", "comp_logo", "home", "home_logo", "away",
		"away_logo", "home_score", "away_score",
		"match_status", "match_detail_status", "raw_match_status",
		"home_en", "away_en", "comp_short_en",
	}
)

func CrateMatch(a []InsertMatchInterface) {
	records := make([]models_sports.BasketballMatch, 0)
	for _, c := range a {
		records = append(records, c.Get())
	}
	if len(records) == 0 {
		return
	}
	clauses := clause.OnConflict{
		Columns: []clause.Column{{Name: "id"}},
		//"time_played", 进行中的时间不更新
		DoUpdates: clause.AssignmentColumns(matchFiled),
	}
	err := global2.Sport().Model(records).Clauses(clauses).CreateInBatches(records, 100).Error
	if err != nil {
		return
	}
	batchToMatchTempSchedule(transTo(records))

}

func transTo(records []models_sports.BasketballMatch) []models_sports.MatchTempSchedule {
	data := make([]models_sports.MatchTempSchedule, 0)
	var compIds []int
	var teamIds []int
	for _, r := range records {
		compIds = append(compIds, r.CompetitionID)
		teamIds = append(teamIds, r.HomeTeamID)
		teamIds = append(teamIds, r.AwayTeamID)
		// 转换成数组运算
	}

	teamMap, _ := GetTeamIdMaps(teamIds)
	competitionMap, _ := GetCompetitionIdMaps(compIds)
	for _, c := range records {
		var homeScores []int
		var awayScores []int
		json.Unmarshal([]byte(c.HomeScores), &homeScores)
		json.Unmarshal([]byte(c.AwayScores), &awayScores)
		comp, ok := competitionMap[c.CompetitionID]
		if !ok {
			// 空数据没匹配到
			comp = models_sports.BasketballCompetition{}
		}
		found := true
		hTeam, ok := teamMap[c.HomeTeamID]
		if !ok {
			global2.Log.Info("basketball team id:%v,not found", c.HomeTeamID)
			// 空数据没匹配到
			hTeam = models_sports.BasketballTeam{}
			found = false
		}
		aTeam, ok := teamMap[c.AwayTeamID]
		if !ok {
			global2.Log.Info("basketball team id:%v,not found", c.AwayTeamID)
			// 空数据没匹配到
			aTeam = models_sports.BasketballTeam{}
			found = false
		}
		if !found {
			continue
		}
		if aTeam.ShortNameEn == "" {
			aTeam.ShortNameEn = "lmbak"
			if aTeam.NameEn != "" {
				aTeam.ShortNameEn = aTeam.NameEn
			}
		}
		if hTeam.ShortNameEn == "" {
			hTeam.ShortNameEn = "lmbak"
			if hTeam.NameEn != "" {
				hTeam.ShortNameEn = hTeam.NameEn
			}
		}
		if comp.ShortNameEn == "" {
			comp.ShortNameEn = "lmcomp"
			if comp.NameZh != "" {
				comp.ShortNameEn = comp.NameZh
			}
		}
		if comp.ShortNameZh == "" {
			comp.ShortNameZh = comp.NameZh
		}
		if hTeam.ShortNameZh == "" {
			hTeam.ShortNameZh = hTeam.NameZh
		}
		if aTeam.ShortNameZh == "" {
			aTeam.ShortNameZh = aTeam.NameZh
		}

		temp := models_sports.MatchTempSchedule{
			MatchId:           c.ID,
			MatchTime:         c.MatchTime,
			SportId:           config.BasketBall,
			Comp:              comp.NameZh,
			CompShortZh:       comp.ShortNameZh,
			CompLogo:          comp.Logo,
			Home:              hTeam.ShortNameZh,
			HomeLogo:          hTeam.Logo,
			Away:              aTeam.ShortNameZh,
			AwayLogo:          aTeam.Logo,
			HomeScore:         uint32(Sum(homeScores)),
			AwayScore:         uint32(Sum(awayScores)),
			MatchStatus:       c.StatusID.MatchTempScheduleStatus(),
			RawMatchStatus:    uint32(c.StatusID),
			MatchDetailStatus: c.StatusID.ToString(),
			TimePlayed:        c.TimePlayed,
			AwayEn:            aTeam.ShortNameEn,
			HomeEn:            hTeam.ShortNameEn,
			CompShortEn:       comp.ShortNameEn,
		}
		data = append(data, temp)
	}
	return data
}

func batchToMatchTempSchedule(records []models_sports.MatchTempSchedule) {
	if len(records) == 0 {
		return
	}
	clauses := clause.OnConflict{
		Columns: []clause.Column{{Name: "match_id"}},
		//"time_played", 进行中的时间不更新
		// "flag", 自定义FLAG
		DoUpdates: clause.AssignmentColumns(matchTempField),
	}
	err := global2.Sport().Model(records).Clauses(clauses).CreateInBatches(records, 100).Error
	if err != nil {
		return
	}
}

func GetMatchTime() int {
	var data models_sports.BasketballMatch
	err := global2.Sport().Model(&data).Order("updated_at DESC").Limit(1).Take(&data).Error
	if err != nil {
		return 0
	}
	return data.UpdatedAt
}

func GetMatchId() int {
	var data models_sports.BasketballMatch
	err := global2.Sport().Model(&data).Order("id DESC").Limit(1).Take(&data).Error
	if err != nil {
		return 0
	}
	return data.ID
}

func DeleteMatch(ids []int) {
	if len(ids) == 0 {
		return
	}
	var model models_sports.BasketballMatch
	err := global2.Sport().Where("id in ?", ids).Delete(&model).Error
	if err != nil {
		global2.Log.Error("删除赛程失败：", err, "ids: ", ids)
		return
	}
	services.DeleteMatchSchedule(ids, config.BasketBall)
}
func GetByExists(update models_sports.BasketballMatch) bool {
	marshal, _ := json.Marshal(update)
	md5 := encrypt.Md5(string(marshal))
	nx := global2.GetRds().SetNX("basketball_update:"+md5, "", time.Second*300)
	if !nx.Val() {
		//global.Log.Error("该记录命中缓存，无需修改：", string(marshal))
		return true
	}
	return false
}
func UpdateMatchScore(a []UpdateMatchInterface) {
	records := make([]models_sports.BasketballMatch, 0)
	for _, c := range a {
		update := c.GetUpdate()
		if GetByExists(update) {
			continue
		}
		records = append(records, update)
	}
	if len(records) == 0 {
		return
	}
	// 目前只更新这几个字段
	updateFields := []string{
		"id", "status_id", "home_scores", "away_scores", "time_played",
	}
	for k, record := range records {
		err := global2.Sport().Transaction(func(tx *gorm.DB) error {
			match := models_sports.BasketballMatch{}
			err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
				Where("id", record.ID).
				Limit(1).
				Find(&match).
				Error
			if err != nil {
				if err == gorm.ErrRecordNotFound {
					return nil
				}
				return err
			}
			records[k].HomeTeamID = match.HomeTeamID
			records[k].AwayTeamID = match.AwayTeamID
			records[k].CompetitionID = match.CompetitionID
			err = tx.Model(record).Select(updateFields).Updates(record).Error
			if err != nil {
				return err
			}
			return nil
		})
		if err != nil {
			global2.Log.Info("篮球更新失败: ", err)
			continue
		}

	}
	updateTempScheduleScore(transTo(records))
}

func updateTempScheduleScore(records []models_sports.MatchTempSchedule) {
	updateFields := []string{
		"match_id", "match_status", "match_detail_status",
		"home_score", "away_score", "time_played", "raw_match_status",
	}
	for _, record := range records {
		err := global2.Sport().Model(record).
			Select(updateFields).
			Where("match_id = ? and sport_id = ?", record.MatchId, config.BasketBall).
			Updates(record).
			Error
		if err != nil {
			return
		}
	}
}

// UpdateMatchAllField 更新赛事所有字段
// ⚠️ ⚠️ ⚠️ ⚠️ ⚠️
// 慎用，这个只是专门提供给recent行为使用
// 因为我们不知道recent 会不会改变对手等一系列的数据
// 其他情况请自己斟酌
func UpdateMatchAllField(a []UpdateMatchInterface) {
	records := make([]models_sports.BasketballMatch, 0)
	for _, c := range a {
		update := c.GetUpdate()
		if GetByExists(update) {
			continue
		}
		records = append(records, update)
	}
	if len(records) == 0 {
		return
	}
	//for _, record := range records {
	//	err := global.Sport().Transaction(func(tx *gorm.DB) error {
	//		match := models_sports.BasketballMatch{}
	//		err := tx.Clauses(clause.Locking{Strength: "UPDATE"}).
	//			Where("id", record.ID).
	//			Limit(1).
	//			Find(&match).
	//			Error
	//
	//		if err != nil {
	//			if err == gorm.ErrRecordNotFound {
	//				return nil
	//			}
	//			return err
	//		}
	//		err = tx.Model(record).Select(strings.Join(matchFiled, ",")).Updates(record).Error
	//		if err != nil {
	//			return err
	//		}
	//		return nil
	//	})
	//	if err != nil {
	//		global.Log.Info("篮球更新失败: ", err)
	//		continue
	//	}
	//
	//}

	clauses := clause.OnConflict{
		Columns:   []clause.Column{{Name: "id"}},
		DoUpdates: clause.AssignmentColumns(matchFiled),
	}
	err := global2.Sport().Model(records).Clauses(clauses).CreateInBatches(records, 100).Error
	if err != nil {
		global2.Log.Error(" update error: ", err)
	}
	updateTempScheduleAll(transTo(records))
}

// updateTempScheduleAll 更新赛事所有字段
// ⚠️ ⚠️ ⚠️ ⚠️ ⚠️
// 慎用，这个只是专门提供给recent行为使用
// 因为我们不知道recent 会不会改变对手等一系列的数据
// 其他情况请自己斟酌
func updateTempScheduleAll(records []models_sports.MatchTempSchedule) {
	//for _, record := range records {
	//	err := global.Sport().Model(record).
	//		Select(strings.Join(matchTempField, ",")).
	//		Where("match_id = ? and sport_id = ?", record.MatchId, config.BasketBall).
	//		Updates(record).Error
	//	if err != nil {
	//		return
	//	}
	//}

	clauses := clause.OnConflict{
		Columns:   []clause.Column{{Name: "match_id"}, {Name: "sport_id"}},
		DoUpdates: clause.AssignmentColumns(matchTempField),
	}
	err := global2.Sport().Model(records).Clauses(clauses).CreateInBatches(records, 100).Error
	if err != nil {
		global2.Log.Error(" update error: ", err)
	}
}

func GetTimeBetweenMatchIds(startTime, endTime int64, lastId int) []int {
	model := models_sports.BasketballMatch{}
	records := make([]models_sports.BasketballMatch, 0)
	//"match_time > unix_timestamp( '2022-06-27 00:00:00' ) AND match_time < unix_timestamp( '2022-06-28 00:00:00' )"
	ids := make([]int, 0)
	err := global2.Sport().
		Where("match_time > ?  AND match_time <= ?", startTime, endTime).
		Where("id > ?", lastId).
		Where("status_id in ?", model.GetStartingStatus()).
		Order("id asc").
		Limit(120).
		Find(&records).Error
	if err != nil {
		return ids
	}
	for _, record := range records {
		ids = append(ids, record.ID)
	}
	return ids
}
